package com.test.learnkotlin.viewmodel

import android.app.Application
import com.test.learnkotlin.base.BaseViewModel
import com.test.learnkotlin.model.FlowModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

/*
    https://juejin.cn/post/7001071604855734285

    Flow
    Flow是Google官方提供的一个类似于RxJava的响应式编程模型。它是基于Kotlin协程的。
    它相对于Rxjava具有以下特点：

    具有更友好的API，学习成本较低
    跟Kotlin协程、LiveData结合更紧密，Flow能够转换成LiveData，在ViewModel中直接使用
    结合协程的作用域，当协程被取消时，Flow也会被取消，避免内存泄漏

    我们知道Flow的特点之一就是冷流。那么什么是冷流呢？


    冷流：当数据被订阅的时候，发布者才开始执行发射数据流的代码。并且当有多个订阅者的时候，每一个订阅者何发布者都是一对一的关系，每个订阅者都会收到发布者完整的数据。


    热流：无论有没有订阅者订阅，事件始终都会发生。当热流有多个订阅者时，发布者跟订阅者是一对多的关系，热流可以与多个订阅者共享信息。


    StateFlow
    因为Flow是冷流，这与LiveData的特点完全不一样，因此Flow提供了StateFlow来实现热流。
    StateFlow 是 SharedFlow 的一个比较特殊的变种，而 SharedFlow 又是 Kotlin 数据流当中比较特殊的一种类型。StateFlow 与 LiveData 是最接近的，因为:

    它始终是有值的。
    它的值是唯一的。
    它允许被多个观察者共用 (因此是共享的数据流)。
    它永远只会把最新的值重现给订阅者，这与活跃观察者的数量是无关的。


    官方推荐当暴露 UI 的状态给视图时，应该使用 StateFlow。这是一种安全和高效的观察者，专门用于容纳 UI 状态。
    StateFlow使用
    StateFlow替换掉LiveData是简单的。我们来看看StateFlow的构造函数：


 */
class FlowViewModel(application: Application) : BaseViewModel<FlowModel>(application) {
    var count = 1
    val mutableStateFlow = MutableStateFlow(count)
    val stateFlow: StateFlow<Int> = mutableStateFlow

    fun changeValue() {
        mutableStateFlow.value = count
        count++
    }

    /*
        在ViewModel上游中不断的发送值，View层通过collect函数去获取到上游发送的数据。

        StateFlow只有在值发生改变时才会返回，如果发生更新但值没有变化时，StateFlow不会回调collect函数，但LiveData会进行回调。

        看 MutableStateFlow 源码，其中 compareAndSet 函数，此函数使用Any.equals进行常规比较。如果expect和update都等于当前值，则该函数返回true，但它实际上不会更改存储在值中的引用。

        此方法是线程安全的，可以安全地从并发协程调用，而无需外部同步。

     */
}